using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEditor;

namespace Prota.Unity
{
    /*
    视差模拟.
    cameraDistance: 相机到焦平面(一般是人物所在平面)的距离.
    distance: 物件到焦平面的距离.
    factor: 物件在画面上的移动乘数. 即物件在焦平面上的投影的移动速度比.
    当焦平面的人物移动了距离 relativeDistance 时, 距离为 distance 的物体在焦平面上的投影位移为
    h = relativeDistance / distance * cameraDistance
    此时只需要设置 relativeDistance 为物体的实际位置和人物的距离, 即可算出投影距离h.
    */
    
    [ExecuteAlways]
    [DefaultExecutionOrder(2250)]
    public class Parallax : MonoBehaviour
    {
        public ParallaxCamera cam => ParallaxCamera.instance;
        
        // 把摄像机摆到这个位置时, 物体的投影偏移总为0. 方便调整物体的位置.
        public Transform cameraRef;
        
        // 与焦平面的距离. 正数代表远离相机, 负数代表靠近相机.
        public float distance = 0f;
        
        // 在相机位于 cameraRefPos 时, 该物体相对于 cameraRefPos 的位置.
        public Vector2 relativePosition;
        
        // 相对于相机的位置.
        public Vector2 viewPosition
        {
            get => (this.transform.position - cam.transform.position).ToVec2();
            set => this.transform.SetPositionXY(cam.transform.position.ToVec2() + value);
        }
        
        public Vector2 refToCamPosition => cam.transform.position.ToVec2() - cameraRef.position.ToVec2();
        
        public float objectDistance => distance + cam.distance;
        
        // 注意 Cinemachine 相机控制在 LateUpdate 执行.
        // 除了自己要在 LateUpdate 更新以外, 还要保证优先级超过 CinemachineBrain.
        void LateUpdate()
        {
            UpdatePosition();
        }
        
        void UpdatePosition()
        {
            if(cam == null) return;
            if(cameraRef == null) return;
            
            if(Application.isPlaying)
            {
                SyncPositionFromCameraMove();
            }
            else
            {
                if(Selection.activeGameObject == this.gameObject)
                {
                    SyncPositionFromObjectMove();
                }
                else
                {
                    SyncPositionFromCameraMove();
                }
            }
        }
        
        // 相机被移动, 根据相机和锚点设置 viewPosition.
        void SyncPositionFromCameraMove()
        {
            viewPosition = GetPosition(relativePosition, refToCamPosition, cam.distance, objectDistance);
        }
        
        // 物体被移动, 不改变自己的位置, 根据相机和锚点设置 relativePosition.
        void SyncPositionFromObjectMove()
        {
            relativePosition = GetRevertPosition(viewPosition, refToCamPosition, cam.distance, objectDistance);
        }
        
        // 根据 relativePosition 和 cameraRefPos 计算当前位置.
        static Vector2 GetPosition(Vector2 relativePos, Vector2 refToCamPos, float cameraDistance, float objectDistance)
        {
            var factor = cameraDistance / objectDistance;
            return relativePos - factor * refToCamPos;
        }
        
        // 根据当前位置和 cameraRefPos 计算 relativePosition.
        static Vector2 GetRevertPosition(Vector2 viewPos, Vector2 refToCamPos, float cameraDistance, float objectDistance)
        {
            var factor = cameraDistance / objectDistance;
            return viewPos + factor * refToCamPos;
        }
    }
}
